package com.su.bo.process.util

import com.alibaba.fastjson2.JSON
import com.alibaba.fastjson2.JSONArray
import com.alibaba.fastjson2.JSONObject
import org.dom4j.Node
import org.dom4j.io.SAXReader

@Suppress("unused")
object JsonToJson {
    /**
     * @param dataJson 源数据Json信息
     * @param resultJsonSchema 转义后的Json字符串描述
     * 转义需要在原JsonSchema中填入“valuePath”作为转换的轴字段提取。
     * @return 转换后的Json字符串。
     */
    @JvmStatic
    @Throws(Exception::class)
    fun generateJson(dataJson: String, resultJsonSchema: String): Any? {
        val resultJsonSchemaObj: JSONObject = JSON.parseObject(resultJsonSchema)
        val xml = StringBuffer()
            .append("<root>")
            .append(JsonToXml.toXmlByJson(dataJson))
            .append("</root>").toString()
        when (resultJsonSchemaObj.getString("type")) {
            "array" -> {
                val document = SAXReader().read(xml.byteInputStream())
                val rootNodes: List<Node> =
                    if (JSON.parse(dataJson) is JSONArray)
                        document.selectNodes("/root/array")
                    else
                        document.selectNodes("/root")
                val tempArray = JSONArray()
                for (node in rootNodes)
                    tempArray.addAll((injectionObject(resultJsonSchemaObj, node) as JSONArray?)!!)
                return tempArray.toJSONString()
            }

            "object" -> {
                val rootNode = SAXReader()
                    .read(xml.byteInputStream())
                    .selectSingleNode("/root")
                val jsonObject = injectionObject(resultJsonSchemaObj, rootNode) as JSONObject
                return jsonObject.toJSONString()
            }

            else -> {
                val rootNode = SAXReader()
                    .read(xml.byteInputStream())
                    .selectSingleNode("/root")
                return injectionObject(resultJsonSchemaObj, rootNode)
            }
        }
    }

    @JvmStatic
    private fun injectionObject(resultJsonSchemaObj: JSONObject, node: Node): Any? {
        return when (resultJsonSchemaObj.getString("type")) {
            "array" -> {
                val resultJsonArray = JSONArray()
                val valuePath = resultJsonSchemaObj.getString("value_path")
                for (valueNode in node.selectNodes(valuePath)) {
                    try {
                        resultJsonArray.add(injectionObject(resultJsonSchemaObj.getJSONObject("items"), valueNode))
                    } catch (exception: java.lang.Exception) {
                        throw java.lang.Exception("构建数组【$valuePath】取值映射失败,请检查映射json配置。")
                    }
                }
                resultJsonArray
            }

            "object" -> {
                val resultJsonObject = JSONObject()
                val propertiesJsonObj = resultJsonSchemaObj.getJSONObject("properties")
                for (properties in propertiesJsonObj.keys) {
                    val valueJsonObj = propertiesJsonObj.getJSONObject(properties)
                    try {
                        resultJsonObject[properties] = injectionObject(valueJsonObj, node)
                    } catch (e: java.lang.Exception) {
                        throw java.lang.Exception("查找属性【$properties】取值映射失败,请检查映射json配置。")
                    }
                }
                resultJsonObject
            }

            "string" -> {
                node.selectSingleNode(resultJsonSchemaObj.getString("value_path")).stringValue
            }

            "integer" -> {
                Integer.valueOf(node.selectSingleNode(resultJsonSchemaObj.getString("value_path")).stringValue)
            }

            "boolean" -> {
                var value = node.selectObject(resultJsonSchemaObj.getString("value_path"))
                if (value is Node) {
                    value = value.stringValue
                }
                value
            }

            else -> {
                throw Exception("Type类型解析失败，无法识别注入的数据")
            }
        }
    }
}